/*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "karazhan.h"

enum Yells
{
    SAY_AGGRO					= 0,
    SAY_SPECIAL					= 1,
    SAY_KILL					= 2,
    SAY_DEATH					= 3,
	SAY_OUT_OF_COMBAT			= 4,

	SAY_GUEST					= 0
};

enum Spells
{
    SPELL_VANISH                = 29448,
    SPELL_GARROTE_DUMMY         = 29433,
    SPELL_GARROTE				= 37066,
    SPELL_BLIND                 = 34694,
    SPELL_GOUGE                 = 29425,
    SPELL_FRENZY                = 37023,
	SPELL_DUAL_WIELD			= 29651,
	SPELL_BERSERK				= 26662,
	SPELL_VANISH_TELEPORT		= 29431,
};

enum Misc
{
	EVENT_GUEST_TALK			= 1,
	EVENT_GUEST_TALK2			= 2,
	EVENT_SPELL_VANISH			= 3,
	EVENT_SPELL_GARROTE			= 4,
	EVENT_SPELL_BLIND			= 5,
	EVENT_SPELL_GOUGE			= 6,
	EVENT_CHECK_HEALTH			= 7,
	EVENT_SPELL_ENRAGE			= 8,
	EVENT_KILL_TALK				= 9,

	ACTIVE_GUEST_COUNT			= 4,
	MAX_GUEST_COUNT				= 6
};

const Position GuestsPosition[4] =
{
    {-10987.38f, -1883.38f, 81.73f, 1.50f},
    {-10989.60f, -1881.27f, 81.73f, 0.73f},
    {-10978.81f, -1884.08f, 81.73f, 1.50f},
    {-10976.38f, -1882.59f, 81.73f, 2.31f},
};

const uint32 GuestEntries[6]=
{
    17007,
    19872,
    19873,
    19874,
    19875,
    19876,
};

class boss_moroes : public CreatureScript
{
	public:
		boss_moroes() : CreatureScript("boss_moroes") { }

		struct boss_moroesAI : public BossAI
		{
			boss_moroesAI(Creature* creature) : BossAI(creature, TYPE_MOROES)
			{
				_activeGuests = 0;
			}

			void InitializeAI()
			{
				BossAI::InitializeAI();
				InitializeGuests();
			}

			void JustReachedHome()
			{
				BossAI::JustReachedHome();
				InitializeGuests();
			}

			void InitializeGuests()
			{
				if (!me->IsAlive())
					return;

				if (_activeGuests == 0)
				{
					_activeGuests |= 0x3F;
					uint8 rand1 = RAND(0x01, 0x02, 0x04);
					uint8 rand2 = RAND(0x08, 0x10, 0x20);
					_activeGuests &= ~(rand1|rand2);
				}

				for (uint8 i = 0; i < MAX_GUEST_COUNT; ++i)
					if ((1 << i) & _activeGuests)
						me->SummonCreature(GuestEntries[i], GuestsPosition[summons.size()], TEMPSUMMON_MANUAL_DESPAWN);

				_events2.Reset();
				_events2.ScheduleEvent(EVENT_GUEST_TALK, 10000);
			}

			void Reset()
			{
				BossAI::Reset();
				me->CastSpell(me, SPELL_DUAL_WIELD, true);
			}

			void EnterCombat(Unit* who)
			{
				BossAI::EnterCombat(who);
				Talk(SAY_AGGRO);

				events.ScheduleEvent(EVENT_SPELL_VANISH, 30000);
				events.ScheduleEvent(EVENT_SPELL_BLIND, 20000);
				events.ScheduleEvent(EVENT_SPELL_GOUGE, 13000);
				events.ScheduleEvent(EVENT_CHECK_HEALTH, 5000);
				events.ScheduleEvent(EVENT_SPELL_ENRAGE, 600000);

				_events2.Reset();
				me->CallForHelp(20.0f);
			}

			void KilledUnit(Unit* /*victim*/)
			{
				if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
				{
					Talk(SAY_KILL);
					events.ScheduleEvent(EVENT_KILL_TALK, 5000);
				}
			}

			void JustDied(Unit* killer)
			{
				summons.clear();
				BossAI::JustDied(killer);
				Talk(SAY_DEATH);

				instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GARROTE);
			}

			void JustSummoned(Creature* summon)
			{
				summons.Summon(summon);
			}

			Creature* GetRandomGuest()
			{
				std::list<Creature*> guestList;
				for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ++i)
					if (Creature* summon = ObjectAccessor::GetCreature(*me, *i))
						guestList.push_back(summon);

				return Trinity::Containers::SelectRandomContainerElement(guestList);
			}

			void UpdateAI(uint32 diff)
			{
				_events2.Update(diff);
				switch (_events2.ExecuteEvent())
				{
					case EVENT_GUEST_TALK:
						if (Creature* guest = GetRandomGuest())
							guest->AI()->Talk(SAY_GUEST);
						_events2.ScheduleEvent(EVENT_GUEST_TALK2, 5000);
						break;
					case EVENT_GUEST_TALK2:
						Talk(SAY_OUT_OF_COMBAT);
						_events2.ScheduleEvent(EVENT_GUEST_TALK, urand(60000, 120000));
						break;
				}

				if (!UpdateVictim())
					return;

				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING))
					return;

				switch (events.ExecuteEvent())
				{
					case EVENT_CHECK_HEALTH:
						if (me->HealthBelowPct(31))
						{
							me->CastSpell(me, SPELL_FRENZY, true);
							break;
						}
						events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
						break;
					case EVENT_SPELL_ENRAGE:
						me->CastSpell(me, SPELL_BERSERK, true);
						break;
					case EVENT_SPELL_BLIND:
						if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 10.0f, true))
							me->CastSpell(target, SPELL_BLIND, false);
						events.ScheduleEvent(EVENT_SPELL_BLIND, urand(25000, 40000));
						break;
					case EVENT_SPELL_GOUGE:
						me->CastSpell(me->GetVictim(), SPELL_GOUGE, false);
						events.ScheduleEvent(EVENT_SPELL_GOUGE, urand(25000, 40000));
						return;
					case EVENT_SPELL_VANISH:
						events.DelayEvents(9000);
						events.SetPhase(1);
						me->CastSpell(me, SPELL_VANISH, false);
						events.ScheduleEvent(EVENT_SPELL_VANISH, 30000);
						events.ScheduleEvent(EVENT_SPELL_GARROTE, urand(5000, 7000));
						return;
					case EVENT_SPELL_GARROTE:
						me->CastSpell(me, SPELL_VANISH_TELEPORT, false);
						break;
				}

				// Xinef: not in vanish
				if (events.GetPhaseMask() == 0)
					DoMeleeAttackIfReady();
			}

		private:
			EventMap _events2;
			uint8 _activeGuests;
		};

		CreatureAI* GetAI(Creature* creature) const
		{
			return GetInstanceAI<boss_moroesAI>(creature);
		}
};

class spell_moroes_vanish : public SpellScriptLoader
{
    public:
        spell_moroes_vanish() : SpellScriptLoader("spell_moroes_vanish") { }

        class spell_moroes_vanish_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_moroes_vanish_SpellScript);

            void HandleDummy(SpellEffIndex effIndex)
            {
				PreventHitDefaultEffect(effIndex);
				if (Unit* target = GetHitUnit())
				{
					Position pos;
					target->GetFirstCollisionPosition(pos, 5.0f, M_PI);
					GetCaster()->CastSpell(target, SPELL_GARROTE_DUMMY, true);
					GetCaster()->RemoveAurasDueToSpell(SPELL_VANISH);
					GetCaster()->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), target->GetOrientation());
				}

            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_moroes_vanish_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_moroes_vanish_SpellScript();
        }
};

void AddSC_boss_moroes()
{
    new boss_moroes();
	new spell_moroes_vanish();
}
